﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using matrixdotnet.DBHelperLib;
using matrixdotnet.CommonDAL;

namespace matrixdotnet.CommonDALImp
{
    public class UnitOfWork
    {
        private DBHelper _dbHelper;
        private HashSet<IDataEntity> _dirtyEntities;
        private HashSet<IDataEntity> _newEntities;

        public UnitOfWork(DBHelper dbHelper)
        {
            _dbHelper = dbHelper;
            _dbHelper.BeginTransaction();
        }

        public void RegiterClean(IDataEntity dataEntity)
        {
            dataEntity.Dirty += new EventHandler<DirtyEventArgs>(dataEntity_Dirty);
            dataEntity.ConstraintIntegrity += new EventHandler<ConstraintIntegrityEventArgs>(
                dataEntity_ConstraintIntegrity);
        }
        public void RegisterNew(IDataEntity dataEntity)
        {
            _newEntities.Add(dataEntity);
            dataEntity.ConstraintIntegrity += new EventHandler<ConstraintIntegrityEventArgs>(
                dataEntity_ConstraintIntegrity);
        }

        public void Commit()
        {
            try
            {
                foreach (IDataEntity entity in _newEntities)
                    CreateEntity(entity);

                foreach (IDataEntity entity in _dirtyEntities)
                    UpdateEntity(entity);

                _dbHelper.Commit();

                Clear();
            }
            catch (Exception e)
            {
                Rollback();
                throw e;
            }

        }

        public void Rollback()
        {
            Clear();
            _dbHelper.Rollback();
        }

        void dataEntity_ConstraintIntegrity(object sender, ConstraintIntegrityEventArgs e)
        {
            IDataEntity referencedEntity = e.ReferencedEntity;

            if (_newEntities.Contains(referencedEntity))
            {
                CreateEntity(referencedEntity);
                return;
            }

            if (_dirtyEntities.Contains(referencedEntity))
            {
                UpdateEntity(referencedEntity);
                return;
            }
        }

        void dataEntity_Dirty(object sender, DirtyEventArgs e)
        {
            e.DirtyEntity.Dirty -= new EventHandler<DirtyEventArgs>(dataEntity_Dirty);
            _dirtyEntities.Add(e.DirtyEntity);
        }

        private void Clear()
        {
            _newEntities.Clear();
            _dirtyEntities.Clear();
        }

        private static void CreateEntity(IDataEntity entity)
        {
            if (entity.IsNew)
                entity.Create();
        }

        private static void UpdateEntity(IDataEntity entity)
        {
            if (entity.IsDirty)
                entity.Update();
        }
    }
}
